using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;

namespace Skywave.ComponentModel
{
    public enum FreeIdFinderIdTypes
    {
        Default,
        Flag
    }
    public class FreeIdFinder
    {
        Type numberType;
        ArrayList starts, usedIds;
        Dictionary<object, ArrayList> holes = new Dictionary<object, ArrayList>();
        Dictionary<object, object> tops = new Dictionary<object, object>();
        FreeIdFinderIdTypes IdType;

        public FreeIdFinder(ArrayList inUsedIds, ArrayList inStarts, Type inType)
        {
            Construct(inUsedIds, inStarts, inType);
        }
        public FreeIdFinder(ArrayList inUsedIds, ArrayList inStarts)
        {
            Construct(inUsedIds, inStarts, typeof(int));
        }
        public FreeIdFinder(ArrayList inUsedIds, object start)
        {
            ArrayList outStarts = new ArrayList();
            outStarts.Add(start);
            Construct(inUsedIds, outStarts, start.GetType());
        }
        public FreeIdFinder(ArrayList inUsedIds, object start, FreeIdFinderIdTypes inIdType)
        {
            ArrayList outStarts = new ArrayList();
            IdType = inIdType;
            outStarts.Add(start);
            Construct(inUsedIds, outStarts, start.GetType());
        }
        public FreeIdFinder(ArrayList inUsedIds, Type inType)
        {
            Construct(inUsedIds, new ArrayList(), inType);
        }
        private void Construct(ArrayList inUsedIds, ArrayList inStarts, Type inType)
        {
            starts = new ArrayList();
            foreach (object obj1 in inStarts)
            {
                AddStart(obj1);
            }
            //columnName = inColumnName;
            if (inUsedIds != null) usedIds = inUsedIds;
            if (inType != typeof(int) && inType != typeof(long))
            {
                throw new ArgumentException("Only supports Int32(Integer),Int64(Long)");
            }
            numberType = inType;
            Initialize();
        }

        private void Initialize()
        {
            //object t1;
            //if (dt.Columns.IndexOf(columnName) < 0)
            //    throw new ArgumentException("DataTable don't have ColumnName specified.");
            if (usedIds == null)
                usedIds = new ArrayList();
            //foreach (DataRow row1 in dt.Rows)
            //{
            //    if (row1.RowState != DataRowState.Deleted)
            //    {
            //        t1 = GetColumnValue(row1);
            //        usedIds.Add(t1);
            //    }
            //}

            foreach (object start1 in starts)
            {
                InitializeWithStart(start1);
            }
        }

        //private object GetColumnValue(DataRow inRow)
        //{
        //    object res;
        //    if (dt.Columns[columnName].DataType.Equals(typeof(string)))
        //    {
        //        if (numberType == typeof(long))
        //            res = long.Parse((string)inRow[columnName]);
        //        else if (numberType == typeof(int))
        //            res = int.Parse((string)inRow[columnName]);
        //        else
        //            res = new object();
        //    }
        //    else
        //    {
        //        res = inRow[columnName];
        //    }
        //    return res;
        //}

        private void InitializeWithStart(object start1)
        {
            if (tops.ContainsKey(start1)) tops.Remove(start1);
            tops.Add(start1, start1);
        }

        public void AddStart(object inStart)
        {
            int int1;
            long long1;
            if (numberType == typeof(int))
            {
                int1 = (int)inStart;
                if (IdType == FreeIdFinderIdTypes.Flag && (int1 % 2 != 0)) int1 = 1;
                inStart = int1;
            }
            else if (numberType == typeof(long))
            {
                long1 = (long)inStart;
                if (IdType == FreeIdFinderIdTypes.Flag && (long1 % 2 != 0)) long1 = 1;
                inStart = long1;
            }
            if (!starts.Contains(inStart))
            {
                starts.Add(inStart);
                InitializeWithStart(inStart);
            }
        }

        private bool mAutoAddStart = true;
        public bool AutoAddStart
        {
            get { return mAutoAddStart; }
            set { mAutoAddStart = value; }
        }

        public object GetNextId(object inStart)
        {
            if (!tops.ContainsKey(inStart))
                if (mAutoAddStart)
                    AddStart(inStart);
                else
                    throw new ArgumentException("StartId specified not found!");

            object resault;
            resault = tops[inStart];
            do
            {
                IncreaseOneStep(ref resault);
            } while (usedIds.IndexOf(resault) >= 0);
            usedIds.Add(resault);
            tops[inStart] = resault;

            return resault;
        }

        private void IncreaseOneStep(ref object value)
        {
            if (value != null)
            {
                if (numberType == typeof(int)) //Int
                {
                    value = (IdType == FreeIdFinderIdTypes.Flag) ? (int)value * 2 : (int)value + 1;
                }
                else //Long
                {
                    value = (IdType == FreeIdFinderIdTypes.Flag) ? (long)value * 2 : (long)value + 1;
                }
            }
        }

        //public static long GetFreeID(ArrayList inUsedIds, int targetCol)
        //{
        //    return GetFreeID(inUsedIds, targetCol, 1, null, false);
        //}
        //public static long GetFreeID(ArrayList inUsedIds, int targetCol, long startCode, ArrayList Excepts, bool StartPlusOne)
        //{
        //    long targetID = startCode;
        //    if (StartPlusOne) targetID += 1;
        //    int i;
        //Start1:
        //    for (i = 0; i < targetTable.Rows.Count; i++)
        //    {
        //        if ((targetTable.Rows[i].RowState != DataRowState.Deleted) && ((targetTable.Rows[i][targetCol]) != DBNull.Value) && ((targetTable.Rows[i][targetCol]).ToString() == (targetID).ToString()))
        //        {
        //            targetID += 1;
        //            goto Start1;
        //        }
        //    }
        //    if ((Excepts != null) && Excepts.IndexOf((targetID).ToString()) != -1)
        //    {
        //        targetID += 1;
        //        goto Start1;
        //    }
        //    return targetID;
        //}

        //public static int GetFreeID(ArrayList inUsedIds, string targetCol)
        //{
        //    return GetFreeID(inUsedIds, targetCol, 1, null, false);
        //}
        //public static int GetFreeID(ArrayList inUsedIds, string targetCol, int startCode, ArrayList Excepts, bool StartPlusOne)
        //{
        //    int targetID = startCode;
        //    if (StartPlusOne) targetID += 1;
        //    int i;
        //Start1:
        //    for (i = 0; i < targetTable.Rows.Count; i++)
        //    {
        //        if ((targetTable.Rows[i].RowState != DataRowState.Deleted) && ((targetTable.Rows[i][targetCol]) != DBNull.Value) && ((targetTable.Rows[i][targetCol]).ToString() == (targetID).ToString()))
        //        {
        //            targetID += 1;
        //            goto Start1;
        //        }
        //    }
        //    if ((Excepts != null) && Excepts.IndexOf((targetID).ToString()) != -1)
        //    {
        //        targetID += 1;
        //        goto Start1;
        //    }
        //    return targetID;
        //}
    }
}
